package com.artup.util.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.EnumSet;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FileUtil {
	public static final String OS_NAME = System.getProperty("os.name");

	/**
	 * 日志
	 */
	private static Log logger = LogFactory.getLog(FileUtil.class);
	private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*");

	/**
	 * 递归创建目录结构
	 * 
	 * @param rootDir 上级目录
	 * @param dir 下一级目录
	 * @return 创建成功标识
	 */
	public static boolean createDirecotry(String rootDir, String dir) {
		File file = new File(dir);
		if (file.exists()){
			return true;
		}
		String[] paths = null;

		if (OS_NAME.toLowerCase().indexOf("windows") > -1) {
			paths = dir.split("\\" + File.separator);
		} else {
			paths = dir.split(File.separator);
		}
		String dirPath = rootDir;
		for (String path : paths) {
			dirPath += File.separator + path;
			file = new File(dirPath);
			if (file.exists()) {
				continue;
			}
			if (!file.mkdirs()){
				return false;
			}
		}
		file = new File(dir);
		return file.exists();
	}

	/**
	 * 创建目录
	 * 
	 * @param dir 目录路径
	 * @return 创建成功标识
	 */
	public static boolean createDirecotry(String dir) {
		File file = new File(dir);
		if (file.exists())
			return true;

		String[] paths = null;

		if (OS_NAME.toLowerCase().indexOf("windows") > -1) {
			paths = dir.split("\\" + File.separator);
		} else {
			paths = dir.split(File.separator);
		}
		String dirPath = "";
		for (String path : paths) {
			dirPath = dirPath.equals(File.separator) ? dirPath + path : dirPath
					+ File.separator + path;
			file = new File(dirPath);
			if (file.exists()) {
				continue;
			}
			if (!file.mkdir())
				return false;
		}
		file = new File(dir);
		return file.exists();
	}

	/**
	 * 显示文件大小，输出日志用
	 * 
	 * @param size
	 * @return 格式化的显示
	 */
	public static String displaySize(long size) {
		StringBuilder sb = new StringBuilder();
		String sizeStr = String.valueOf(size);
		int len = sizeStr.length();
		int totalDotSize = (len - 1) / 3;
		int firstDotIdx = len - totalDotSize * 3;
		for (int i = 0; i < len; i++) {
			if (i == firstDotIdx) {
				sb.append(",");
				firstDotIdx += 3;
			}
			sb.append(sizeStr.charAt(i));
		}
		sb.append(" byte");
		return sb.toString();
	}
	
	/**
	 * 将uri转换为路径
	 * 
	 * @param uri
	 * @return 转换后的路径
	 */
	public static String convertUri2FilePath(String uri) {
		// Decode the path.
		try {
			uri = URLDecoder.decode(uri, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			try {
				uri = URLDecoder.decode(uri, "ISO-8859-1");
			} catch (UnsupportedEncodingException e1) {
				throw new Error();
			}
		}
		if (!uri.startsWith("/")) {
			return null;
		}
		// Convert file separators.
		uri = uri.replace('/', File.separatorChar);

		// Simplistic dumb security check.
		// You will have to do something serious in the production environment.
		if (uri.contains(File.separator + '.')
				|| uri.contains('.' + File.separator) || uri.startsWith(".")
				|| uri.endsWith(".") || INSECURE_URI.matcher(uri).matches()) {
			return null;
		}

		// Convert to absolute path.
		// return System.getProperty("user.dir") + uri;
		return uri;
	}

	/**
	 * 获取文件名后缀
	 * 
	 * @param filename 文件名称
	 * @return 文件后缀
	 */
	public static String getExtension(String filename) {
		if ((filename != null) && (filename.length() > 0)) {
			int i = filename.lastIndexOf('.');
			if ((i > -1) && (i < (filename.length() - 1))) {
				return filename.substring(i + 1);
			}
		}
		return null;
	}
	
	/**
	 * 获取文件内容
	 * 
	 * @param source
	 * @param charSet
	 * @return
	 * @throws IOException
	 */
	public static String getFileContent(File source, String charSet)throws IOException {
		StringBuilder buf = new StringBuilder();
		BufferedInputStream fis = null;
		BufferedReader reader = null;
		try {
			fis = new BufferedInputStream(new FileInputStream(source));
			reader = new BufferedReader(new InputStreamReader(fis, charSet), 5 * 1024 * 1024);// 用5M的缓冲读取文本文件
			String line = "";
			while ((line = reader.readLine()) != null) {
				buf.append(line);
			}
		} finally {
			if(reader != null){
				reader.close();
			}
			if(fis != null){
				fis.close();
			} 
		}
		return buf.toString();
	}

	/**
	 * 拷贝文件
	 * 
	 * @param source
	 * @param dest
	 * @param charSet
	 * @throws IOException
	 */
	public static void copyFile(File source, File dest, String charSet)
			throws IOException {

		if (!dest.exists()) {
			dest.createNewFile();
		}
		OutputStream out = null;
		BufferedInputStream fis = null;
		BufferedReader reader = null;
		try {
			out = new FileOutputStream(dest);
			fis = new BufferedInputStream(new FileInputStream(source));
			reader = new BufferedReader(new InputStreamReader(fis, charSet), 5 * 1024 * 1024);// 用5M的缓冲读取文本文件
			String line = "";
			while ((line = reader.readLine()) != null) {
				out.write(line.getBytes(charSet));
				out.write("\r\n".getBytes());
			}
		} finally {
			if(reader != null){
				reader.close();
			}
			if(fis != null){
				fis.close();
			}
			if(out != null){
				out.close();
			}
		}
	}

	/**
	 * 拷贝文件
	 * 
	 * @param source
	 * @param dest
	 * @throws Exception
	 */
	public static void copyFile(File source, File dest) throws Exception {
		if (!dest.exists()) {
			dest.createNewFile();
		}
		InputStream in = null;
		OutputStream out = null;
		try {
			in = new FileInputStream(source);
			out = new FileOutputStream(dest);
			byte[] buf = new byte[1024 * 1024 * 5];
			int len;
			while ((len = in.read(buf)) > 0) {
				out.write(buf, 0, len);
			}
		} finally {
			in.close();
			out.close();
		}
	}
	
	public static void fastCopyFile(File source, File dest) throws Exception {
		FileChannel fileChannel_from = null;
		FileChannel fileChannel_to = null;
		try {
			Path copy_from = Paths.get(source.getAbsolutePath());
			Path copy_to = Paths.get(dest.getAbsolutePath());
			try {
			      Files.deleteIfExists(copy_to);
			  } catch (IOException ex) {
			    log.error(ex.getMessage());
			  }
			
			fileChannel_from = (FileChannel.open(copy_from, EnumSet.of(StandardOpenOption.READ)));
			fileChannel_to = (FileChannel.open(copy_to, EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)));
			fileChannel_from.transferTo(0L, fileChannel_from.size(), fileChannel_to);
		} catch(Exception e){
			e.printStackTrace();
		}finally {
			fileChannel_from.close();
			fileChannel_to.close();
		}
	}

	public static void fastCopyFile(String source, String dest) throws Exception {
		fastCopyFile(new File(source), new File(dest)); 	
	}
	
	/**
	 * 从指定大小拷贝文件，
	 * 
	 * @param source
	 * @param size
	 * @param dest
	 * @return boolean
	 * @throws Exception
	 */
	public static boolean copyFile(File source, long size, File dest)throws Exception {
		RandomAccessFile raf = null;
		BufferedOutputStream out = null;
		try {
			raf = new RandomAccessFile(source, "r");
			raf.seek(size);
			out = new BufferedOutputStream(new FileOutputStream(dest));
			byte[] bytes = new byte[1024 * 1024 * 10];
			int c = 0;
			while ((c = raf.read(bytes)) != -1) {
				out.write(bytes, 0, c);
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null)
					out.flush();
				if (raf != null)
					raf.close();
				if (out != null)
					out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	/**
	 * 追加文件，将fromFile内容追加到toFilePath文件中
	 * 
	 * @param fromFile
	 * @param toFilePath
	 * @return boolean
	 */
	public static boolean appendFile(File fromFile, String toFilePath) {
		RandomAccessFile randomFile = null;
		InputStream in = null;
		try {
			// 打开一个随机访问文件流，按读写方式
			randomFile = new RandomAccessFile(toFilePath, "rw");
			// 文件长度，字节数
			long fileLength = randomFile.length();
			// 将写文件指针移到文件尾。
			randomFile.seek(fileLength);
			// randomFile.writeBytes(content);
			in = new FileInputStream(fromFile);
			byte[] bytes = new byte[1024 * 1024 * 10];
			int c = 0;
			while ((c = in.read(bytes)) != -1) {
				randomFile.write(bytes, 0, c);
			}
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(in != null){
				try {
					in.close();
				} catch (IOException e) { 
					e.printStackTrace();
				}
			}
			if (randomFile != null) {
				try {
					randomFile.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return false;
	}

	/**
	 * 将输入的文件流输出到文件中
	 * 
	 * @param in
	 * @param outFile
	 * @throws Exception
	 */
	public static void writeFile(InputStream in, File outFile) throws Exception {
		OutputStream out = null;
		try {
			out = new FileOutputStream(outFile);
			byte[] buf = new byte[1024 * 1024 * 5];
			int len;
			while ((len = in.read(buf)) > 0) {
				out.write(buf, 0, len);
			}
		}catch(Exception e){
			e.printStackTrace();
		} finally {
			in.close();
			out.close();
		}
	}

	/**
	 * 获取文件流
	 * 
	 * @param filePath
	 * @return 字节数组
	 */
	public static byte[] getBytes(String filePath) {
		byte[] buffer = null;
		try {
			File file = new File(filePath);
			FileInputStream fis = new FileInputStream(file);
			ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
			byte[] b = new byte[1000];
			int n;
			while ((n = fis.read(b)) != -1) {
				bos.write(b, 0, n);
			}
			fis.close();
			bos.close();
			buffer = bos.toByteArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return buffer;
	}

	/**
	 * 获得当前编译后的class的目录 <br/>
	 * get the root dir of this class.
	 * 
	 * @return 路径
	 */
	public static String getClassPath() {
		String path = null;
		ProtectionDomain domain = FileUtil.class.getProtectionDomain();

		if (logger.isDebugEnabled()) {
			logger.debug("==========>>> ProtectionDomain = " + domain);
		}

		CodeSource source = null;
		URL result = null;
		if (domain != null)
			source = domain.getCodeSource();// 获得code source
		if (source != null)
			result = source.getLocation();// 获得URL
		try {
			path = java.net.URLDecoder.decode(result.getFile(), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		if (logger.isDebugEnabled()) {
			logger.debug("==========>>> RootPath===" + path);
		}

		File file = new File(path);
		int webinfIdx = file.getAbsolutePath().toUpperCase().indexOf("WEB-INF");
		if (webinfIdx > -1) {
			String prePath = file.getAbsolutePath().substring(0, webinfIdx);
			path = prePath + "WEB-INF/classes/";
		}
		if (path.endsWith(".class"))
			return file.getParent();

		return path;
	}

	/**
	 * 得到当前上下文路径目录
	 * 
	 * @return 路径
	 */
	public static String getContextPath() {
		String path = null;
		ProtectionDomain domain = FileUtil.class.getProtectionDomain();

		CodeSource source = null;
		URL result = null;
		if (domain != null)
			source = domain.getCodeSource();// 获得code source
		if (source != null)
			result = source.getLocation();// 获得URL
		try {
			path = java.net.URLDecoder.decode(result.getFile(), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		if (logger.isDebugEnabled()) {
			logger.debug("==========>>> RootPath===" + path);
		}

		File file = new File(path);
		int webinfIdx = file.getAbsolutePath().toUpperCase().indexOf("WEB-INF");
		if (webinfIdx > -1) {
			String prePath = file.getAbsolutePath().substring(0, webinfIdx);
			path = prePath; // + "WEB-INF/classes/";
		}
		return path;
	}

	/**
	 * 得到当期java工作目录
	 * 
	 * @return java工作目录
	 */
	public static String getCurrentJavaWorkDir() {
		File f = new File("");
		String path = f.getAbsolutePath();
		// log.info("==========>>> CurrentJavaWorkDirPath==="+path);
		return path;

	}

	public static void main(String[] arg) {
		String x = FileUtil.getCurrentJavaWorkDir();
		// 当期java工作目录
		System.out.println("x=" + x);
		x = FileUtil.getClassPath();
		System.out.println("x2=" + x);
		x = getContextPath();
		System.out.println("x3=" + x);

	}
}
